/*
 * Sphinx search overrides
 */

var rtddata = require('./rtd-data');
var xss = require('xss/lib/index');
var MAX_RESULT_PER_SECTION = 3;
var MAX_SUBSTRING_LIMIT = 100;

/**
 * Use try...catch block to append html to contents
 *
 * @param {Object} contents html element on which additional html is be appended
 * @param {String} template underscore.js template string
 * @param {Object} data template vars and their values
 */
function append_html_to_contents(contents, template, data) {
    // underscore.js throws variable not defined error
    // because of change of syntax in new versions.
    // See: https://stackoverflow.com/a/25881231/8601393
    try {
        // this is the pre-1.7 syntax from Underscore.js
        contents.append(
            $u.template(
                template,
                data
            )
        );
    }
    catch (error) {
        // this is the new syntax
        contents.append(
            $u.template(template)(data)
        );
    }
}

/*
 * Search query override for hitting our local API instead of the standard
 * Sphinx indexer. This will fall back to the standard indexer on an API
 * failure,
 */
function attach_elastic_search_query(data) {
    var project = data.project;
    var version = data.version;
    var language = data.language || 'en';
    var api_host = data.api_host;

    var query_override = function (query) {
        var search_def = $.Deferred();
        var search_url = document.createElement('a');

        search_url.href = api_host;
        search_url.pathname = '/api/v2/docsearch/';
        search_url.search = '?q=' + $.urlencode(query) + '&project=' + project +
                            '&version=' + version + '&language=' + language;

        search_def
            .then(function (data) {
                var hit_list = data.results || [];
                var total_count = data.count || 0;

                if (hit_list.length) {
                    for (var i = 0; i < hit_list.length; i += 1) {
                        var doc = hit_list[i];
                        var highlight = doc.highlight;
                        var inner_hits = doc.inner_hits || [];
                        var list_item = $('<li style="display: none;"></li>');

                        var title = doc.title;
                        // if highlighted title is present,
                        // use that.
                        if (highlight) {
                            if (highlight.title) {
                                title = xss(highlight.title[0]);
                            }
                        }

                        // Creating the result from elements
                        var suffix = DOCUMENTATION_OPTIONS.FILE_SUFFIX;
                        // Since sphinx 2.2.1 FILE_SUFFIX is .html for all builders,
                        // and there is a new BUILDER option.
                        if ('BUILDER' in DOCUMENTATION_OPTIONS && DOCUMENTATION_OPTIONS.BUILDER === 'readthedocsdirhtml') {
                          suffix = '';
                        }
                        var link = doc.link + suffix;

                        var item = $('<a>', {'href': link});

                        item.html(title);
                        item.find('span').addClass('highlighted');
                        list_item.append(item);

                        // If the document is from subproject, add extra information
                        if (doc.project !== project) {
                            var text = " (from project " + doc.project + ")";
                            var extra = $('<span>', {'text': text});
                            list_item.append(extra);
                        }

                        for (var j = 0; j < inner_hits.length; j += 1) {

                            var contents = $('<div class="context">');

                            var section = "";
                            var section_subtitle = "";
                            var section_subtitle_link = "";
                            var section_content = "";
                            var content = "";

                            var domain = "";
                            var domain_role_name = "";
                            var domain_subtitle_link = "";
                            var domain_name = "";
                            var domain_subtitle = "";
                            var domain_content = "";
                            var domain_docstrings = "";

                            var section_template = '' +
                                '<div>' +
                                    '<a href="<%= section_subtitle_link %>">' +
                                        '<%= section_subtitle %>' +
                                    '</a>' +
                                '</div>' +
                                '<% for (var i = 0; i < section_content.length; ++i) { %>' +
                                    '<div>' +
                                        '<%= section_content[i] %>' +
                                    '</div>' +
                                '<% } %>';

                            var domain_template = '' +
                                '<div>' +
                                    '<a href="<%= domain_subtitle_link %>">' +
                                        '<%= domain_subtitle %>' +
                                    '</a>' +
                                '</div>' +
                                '<div>' +
                                    '<%= domain_content %>' +
                                '</div>';

                            // if the result is page section
                            if(inner_hits[j].type === "sections") {

                                section = inner_hits[j];
                                section_subtitle = section._source.title;
                                section_subtitle_link = link + "#" + section._source.id;
                                section_content = [section._source.content.substr(0, MAX_SUBSTRING_LIMIT) + " ..."];

                                if (section.highlight) {
                                    if (section.highlight["sections.title"]) {
                                        section_subtitle = xss(section.highlight["sections.title"][0]);
                                    }

                                    if (section.highlight["sections.content"]) {
                                        content = section.highlight["sections.content"];
                                        section_content = [];
                                        for (
                                            var k = 0;
                                            k < content.length && k < MAX_RESULT_PER_SECTION;
                                             k += 1
                                        ) {
                                            section_content.push("... " + xss(content[k]) + " ...");
                                        }
                                    }
                                }

                                append_html_to_contents(
                                    contents,
                                    section_template,
                                    {
                                        section_subtitle_link: section_subtitle_link,
                                        section_subtitle: section_subtitle,
                                        section_content: section_content
                                    }
                                );
                            }

                            // if the result is a sphinx domain object
                            if (inner_hits[j].type === "domains") {

                                domain = inner_hits[j];
                                domain_role_name = domain._source.role_name;
                                domain_subtitle_link = link + "#" + domain._source.anchor;
                                domain_name = domain._source.name;
                                domain_subtitle = "";
                                domain_content = "";
                                domain_docstrings = "";

                                if (domain._source.docstrings !== "") {
                                    domain_docstrings = domain._source.docstrings.substr(0, MAX_SUBSTRING_LIMIT) + " ...";
                                }

                                if (domain.highlight) {
                                    if (domain.highlight["domains.docstrings"]) {
                                        domain_docstrings = "... " + xss(domain.highlight["domains.docstrings"][0]) + " ...";
                                    }

                                    if (domain.highlight["domains.name"]) {
                                        domain_name = xss(domain.highlight["domains.name"][0]);
                                    }
                                }

                                domain_subtitle = "[" + domain_role_name + "]: " + domain_name;
                                domain_content = domain_docstrings;

                                append_html_to_contents(
                                    contents,
                                    domain_template,
                                    {
                                        domain_subtitle_link: domain_subtitle_link,
                                        domain_subtitle: domain_subtitle,
                                        domain_content: domain_content
                                    }
                                );
                            }

                            contents.find('span').addClass('highlighted');
                            list_item.append(contents);

                            // Create some spacing between the results.
                            // Also, don't add this spacing in the last hit.
                            if (j !== inner_hits.length - 1) {
                                list_item.append($("<div class='rtd_search_hits_spacing'></div>"));
                            }
                        }

                        Search.output.append(list_item);
                        list_item.slideDown(5);
                    }
                }

                if (!hit_list.length) {
                    // Fallback to Sphinx's indexes
                    Search.query_fallback(query);
                    console.log('Read the Docs search failed. Falling back to Sphinx search.');
                }
                else {
                    Search.status.text(
                        _('Search finished, found %s page(s) matching the search query.').replace('%s', hit_list.length)
                    );
                }
            })
            .fail(function (error) {
                // Fallback to Sphinx's indexes
                Search.query_fallback(query);
            })
            .always(function () {
                $('#search-progress').empty();
                Search.stopPulse();
                Search.title.text(_('Search Results'));
                Search.status.fadeIn(500);
            });

        $.ajax({
            url: search_url.href,
            crossDomain: true,
            xhrFields: {
                withCredentials: true,
            },
            complete: function (resp, status_code) {
                if (
                    status_code !== 'success' ||
                    typeof (resp.responseJSON) === 'undefined' ||
                    resp.responseJSON.count === 0
                ) {
                    return search_def.reject();
                }
                return search_def.resolve(resp.responseJSON);
            }
        })
        .fail(function (resp, status_code, error) {
            return search_def.reject();
        });
    };

    if (typeof Search !== 'undefined' && project && version) {

        // Do not replace the built-in search if RTD's docsearch is disabled
        if (!data.features || !data.features.docsearch_disabled) {
            var query_fallback = Search.query;
            Search.query_fallback = query_fallback;
            Search.query = query_override;
        }
    }
    $(document).ready(function () {
        if (typeof Search !== 'undefined') {
            Search.init();
        }
    });
}


function init() {
    var data = rtddata.get();
    attach_elastic_search_query(data);
}

module.exports = {
    init: init
};
